| Conditions | 16 | 
| Paths | 8910 | 
| Total Lines | 69 | 
| Lines | 0 | 
| Ratio | 0 % | 
| Changes | 0 | ||
Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.
For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.
Commonly applied refactorings include:
If many parameters/temporary variables are present:
Complex classes like Aes.Ctr.encrypt often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
| 1 | /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ | ||
| 38 | Aes.Ctr.encrypt = function(plaintext, password, nBits) { | ||
| 39 | var blockSize = 16; // block size fixed at 16 bytes / 128 bits (Nb=4) for AES | ||
| 40 |     if (!(nBits==128 || nBits==192 || nBits==256)) throw new Error('Key size is not 128 / 192 / 256'); | ||
| 41 | plaintext = String(plaintext).utf8Encode(); | ||
| 42 | password = String(password).utf8Encode(); | ||
| 43 | |||
| 44 | // use AES itself to encrypt password to get cipher key (using plain password as source for key | ||
| 45 | // expansion) - gives us well encrypted key (though hashed key might be preferred for prod'n use) | ||
| 46 | var nBytes = nBits/8; // no bytes in key (16/24/32) | ||
| 47 | var pwBytes = new Array(nBytes); | ||
| 48 |     for (var i=0; i<nBytes; i++) {  // use 1st 16/24/32 chars of password for key | ||
| 49 | pwBytes[i] = i<password.length ? password.charCodeAt(i) : 0; | ||
| 50 | } | ||
| 51 | var key = Aes.cipher(pwBytes, Aes.keyExpansion(pwBytes)); // gives us 16-byte key | ||
| 52 | key = key.concat(key.slice(0, nBytes-16)); // expand key to 16/24/32 bytes long | ||
| 53 | |||
| 54 | // initialise 1st 8 bytes of counter block with nonce (NIST SP800-38A §B.2): [0-1] = millisec, | ||
| 55 | // [2-3] = random, [4-7] = seconds, together giving full sub-millisec uniqueness up to Feb 2106 | ||
| 56 | var counterBlock = new Array(blockSize); | ||
| 57 | |||
| 58 | var nonce = (new Date()).getTime(); // timestamp: milliseconds since 1-Jan-1970 | ||
| 59 | var nonceMs = nonce%1000; | ||
| 60 | var nonceSec = Math.floor(nonce/1000); | ||
| 61 | var nonceRnd = Math.floor(Math.random()*0xffff); | ||
| 62 | // for debugging: nonce = nonceMs = nonceSec = nonceRnd = 0; | ||
| 63 | |||
| 64 | for (var i=0; i<2; i++) counterBlock[i] = (nonceMs >>> i*8) & 0xff; | ||
| 65 | for (var i=0; i<2; i++) counterBlock[i+2] = (nonceRnd >>> i*8) & 0xff; | ||
| 66 | for (var i=0; i<4; i++) counterBlock[i+4] = (nonceSec >>> i*8) & 0xff; | ||
| 67 | |||
| 68 | // and convert it to a string to go on the front of the ciphertext | ||
| 69 | var ctrTxt = ''; | ||
| 70 | for (var i=0; i<8; i++) ctrTxt += String.fromCharCode(counterBlock[i]); | ||
| 71 | |||
| 72 | // generate key schedule - an expansion of the key into distinct Key Rounds for each round | ||
| 73 | var keySchedule = Aes.keyExpansion(key); | ||
| 74 | |||
| 75 | var blockCount = Math.ceil(plaintext.length/blockSize); | ||
| 76 | var ciphertext = ''; | ||
| 77 | |||
| 78 |     for (var b=0; b<blockCount; b++) { | ||
| 79 | // set counter (block #) in last 8 bytes of counter block (leaving nonce in 1st 8 bytes) | ||
| 80 | // done in two stages for 32-bit ops: using two words allows us to go past 2^32 blocks (68GB) | ||
| 81 | for (var c=0; c<4; c++) counterBlock[15-c] = (b >>> c*8) & 0xff; | ||
| 82 | for (var c=0; c<4; c++) counterBlock[15-c-4] = (b/0x100000000 >>> c*8); | ||
| 83 | |||
| 84 | var cipherCntr = Aes.cipher(counterBlock, keySchedule); // -- encrypt counter block -- | ||
| 85 | |||
| 86 | // block size is reduced on final block | ||
| 87 | var blockLength = b<blockCount-1 ? blockSize : (plaintext.length-1)%blockSize+1; | ||
| 88 | var cipherChar = new Array(blockLength); | ||
| 89 | |||
| 90 |         for (var i=0; i<blockLength; i++) { | ||
| 91 | // -- xor plaintext with ciphered counter char-by-char -- | ||
| 92 | cipherChar[i] = cipherCntr[i] ^ plaintext.charCodeAt(b*blockSize+i); | ||
| 93 | cipherChar[i] = String.fromCharCode(cipherChar[i]); | ||
| 94 | } | ||
| 95 |         ciphertext += cipherChar.join(''); | ||
| 96 | |||
| 97 | // if within web worker, announce progress every 1000 blocks (roughly every 50ms) | ||
| 98 |         if (typeof WorkerGlobalScope != 'undefined' && self instanceof WorkerGlobalScope) { | ||
| 99 |             if (b%1000 == 0) self.postMessage({ progress: b/blockCount }); | ||
| 100 | } | ||
| 101 | } | ||
| 102 | |||
| 103 | ciphertext = (ctrTxt+ciphertext).base64Encode(); | ||
| 104 | |||
| 105 | return ciphertext; | ||
| 106 | }; | ||
| 107 | |||
| 226 |